package assembler

import (
	"errors"
	"gitee.com/duxm0114/duxm-scan/pkg/query-service/infrastructure/base/userinterface/rest/dto"
	"github.com/kataras/iris/v12"
)

type BaseAssembler struct {
}

type Options struct {
	allowNull *bool
}

func NewOptions() *Options {
	return &Options{
		allowNull: nil,
	}
}

func (a *BaseAssembler) AssFindByIdRequest(ictx iris.Context) (*dto.FindByIdRequest, error) {
	tenantId, err := a.GetTenantId(ictx)
	if err != nil {
		return nil, err
	}
	id, err := a.GetId(ictx)
	if err != nil {
		return nil, err
	}
	return &dto.FindByIdRequest{
		TenantId: tenantId,
		Id:       id,
	}, nil
}

func (a *BaseAssembler) AssFindByIdsRequest(ictx iris.Context) (*dto.FindByIdsRequest, error) {
	tenantId, err := a.GetTenantId(ictx)
	if err != nil {
		return nil, err
	}
	ids, err := a.GetIds(ictx)
	if err != nil {
		return nil, err
	}
	return &dto.FindByIdsRequest{
		TenantId: tenantId,
		Ids:      ids,
	}, nil
}

func (a *BaseAssembler) AssFindAllRequest(ictx iris.Context) (*dto.FindAllRequest, error) {
	tenantId, err := a.GetTenantId(ictx)
	if err != nil {
		return nil, err
	}
	return &dto.FindAllRequest{
		TenantId: tenantId,
	}, nil
}

func (a *BaseAssembler) AssFindPagingRequest(ictx iris.Context) (*dto.FindPagingRequest, error) {
	tenantId, err := a.GetTenantId(ictx)
	if err != nil {
		return nil, err
	}
	pageNum := ictx.URLParamInt64Default("page-num", 0)
	pageSize := ictx.URLParamInt64Default("page-size", 20)
	filter := ictx.URLParamDefault("filter", "")
	sort := ictx.URLParamDefault("sort", "")
	fields := ictx.URLParamDefault("fields", "")
	return &dto.FindPagingRequest{
		TenantId: tenantId,
		PageNum:  pageNum,
		PageSize: pageSize,
		Filter:   filter,
		Sort:     sort,
		Fields:   fields,
	}, nil
}

func (a *BaseAssembler) GetTenantId(ictx iris.Context, opts ...*Options) (string, error) {
	return a.GetValueByUrlParam(ictx, "tenantId", opts...)
}

func (a *BaseAssembler) GetId(ictx iris.Context, opts ...*Options) (string, error) {
	return a.GetValueByUrlParam(ictx, "id", opts...)
}

func (a *BaseAssembler) GetIds(ictx iris.Context, opts ...*Options) ([]string, error) {
	return a.GetValuesByUrlParam(ictx, "id", opts...)
}

//
// GetValueByUrlParam
// @Description: 从URL的参数中获取string类变量
// @receiver a
// @param ictx iris上下文
// @param name 变量名
// @param opts 可选项
// @return string 返回值
// @return error 错误
//
func (a *BaseAssembler) GetValueByUrlParam(ictx iris.Context, name string, opts ...*Options) (string, error) {
	options := NewOptions().Merge(opts)
	val := ictx.URLParamDefault(name, "")
	if val == "" && !options.GetAllowNull() {
		return "", errors.New(name + " is not empty")
	}
	return val, nil
}

//
// GetValuesByUrlParam
// @Description: 从URL的参数中获取[]string变量
// @receiver a
// @param ictx iris上下文
// @param name 变量名
// @param opts 可选项
// @return string 返回值
// @return error 错误
//
func (a *BaseAssembler) GetValuesByUrlParam(ictx iris.Context, name string, opts ...*Options) ([]string, error) {
	options := NewOptions().Merge(opts)
	values := ictx.URLParamSlice(name)
	if len(values) == 0 && !options.GetAllowNull() {
		return nil, errors.New(name + " is not empty")
	}
	return values, nil
}

//
// GetValueByUrlPath
// @Description: 从URL路径中中获取string变量
// @receiver a
// @param ictx iris上下文
// @param name 变量名
// @param opts 可选项
// @return string 返回值
// @return error 错误
//
func (a *BaseAssembler) GetValueByUrlPath(ictx iris.Context, name string, opts ...*Options) (string, error) {
	options := NewOptions().Merge(opts)
	id := ictx.Params().GetStringDefault(name, "")
	if id == "" && !options.GetAllowNull() {
		return "", errors.New(name + " is not empty")
	}
	return id, nil
}

func (o *Options) Merge(opts []*Options) *Options {
	for _, i := range opts {
		if i.allowNull != nil {
			o.allowNull = i.allowNull
		}
	}
	return o
}

func (o *Options) SetAllowNull(v bool) *Options {
	o.allowNull = &v
	return o
}

func (o *Options) GetAllowNull() bool {
	if o.allowNull != nil {
		return *o.allowNull
	}
	return false
}
